#include "gkt_bit.h"
#include "gkt_crc32.h"

uint32_t crc32_calc_in_reverse_true(uint32_t poly, 
					uint32_t crc_init, 
					const uint8_t *data, uint32_t length)
{
	uint32_t crc_value = crc_init;
	uint8_t byte;
	uint32_t i, j;

	for (i = 0; i < length; i++) {
		gkt_bit_reverse_u8(data[i], byte);
		crc_value ^= (uint32_t)byte << 24;
		for (j = 0; j < 8; j++) {
			if (crc_value & 0x80000000)
				crc_value = (crc_value << 1) ^ poly;
			else
				crc_value = crc_value << 1;
		}
	}

	return crc_value;
}

uint32_t crc32_calc_in_reverse_false(uint32_t poly, 
					uint32_t crc_init, 
					const uint8_t *data, uint32_t length)
{
	uint32_t crc_value = crc_init;
	uint32_t i, j;

	for (i = 0; i < length; i++) {
		crc_value ^= (uint32_t)data[i] << 24;
		for (j = 0; j < 8; j++) {
			if (crc_value & 0x80000000)
				crc_value = (crc_value << 1) ^ poly;
			else
				crc_value = crc_value << 1;
		}
	}

	return crc_value;
}

uint32_t gkt_crc32(const uint8_t *data, uint32_t length)
{
	uint32_t crc_value = GKT_CRC32_INIT;

	if (data && length) {
		crc_value = crc32_calc_in_reverse_true(
							GKT_CRC32_POLY, crc_value, 
							data, length);
		gkt_bit_reverse_u32(crc_value, crc_value);
		crc_value ^= GKT_CRC32_OUT_XOR;
	}

	return crc_value;
}

uint32_t gkt_crc32_mpeg2(const uint8_t *data, uint32_t length)
{
	uint32_t crc_value = GKT_CRC32_MPEG2_INIT;

	if (data && length)
		crc_value = crc32_calc_in_reverse_false(
							GKT_CRC32_MPEG2_POLY, 
							crc_value, data, length);

	return crc_value;
}

